package ntut.andengine.gamedesign;

import java.util.ArrayList;
import java.util.List;

import ntut.andengine.events.UpdateEmitter;
import ntut.andengine.physics.ContactEvent;
import ntut.andengine.physics.PhysicalComponent;
import ntut.andengine.physics.PhysicalComponent.ComponentColor;
import ntut.andengine.physics.Player;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;

import android.content.Context;
import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;

public class GameSceneLevel extends GameScene implements IOnSceneTouchListener {

	// ===========================================================
	// Constants
	// ===========================================================

	public static final short CATEGORYBIT_WHITE = 0x01 << 1;
	public static final short CATEGORYBIT_RED = 0x01 << 2;
	public static final short CATEGORYBIT_BLUE = 0x01 << 3;
 
	public static final short MASKBITS_WHITE = CATEGORYBIT_WHITE + CATEGORYBIT_RED + CATEGORYBIT_BLUE;
	public static final short MASKBITS_RED = CATEGORYBIT_WHITE + CATEGORYBIT_RED;
	public static final short MASKBITS_BLUE = CATEGORYBIT_WHITE + CATEGORYBIT_BLUE;
	
	// ===========================================================
	// Fields
	// ===========================================================

	protected PhysicsWorld mPhysicsWorld;
	Player mSparkle;
	List<UpdateEmitter> listeners;
	List<PhysicalComponent> mPhysicalComponentList;
	
	// ===========================================================
	// Constructors
	// ===========================================================

	public GameSceneLevel(Context context, Engine engine) {
		super(context, engine);
		
		listeners = new ArrayList<UpdateEmitter>();
		mPhysicalComponentList = new ArrayList<PhysicalComponent>();
	}
	
	// ===========================================================
	// Getter & Setter
	// ===========================================================

	public PhysicsWorld getPhysicsWorld(){
		return mPhysicsWorld;
	}
	
	public List<PhysicalComponent> getPhysicalComponentList(){
		return mPhysicalComponentList;
	}
	
	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	@Override
	public Engine onLoadEngine() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public void onLoadResources() {
		
		this.mPhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);

		mPhysicsWorld.setContactListener(new ContactListener(){

			@Override
			public void beginContact(Contact contact) {
				
				Body A = contact.getFixtureA().getBody();
				Body B = contact.getFixtureB().getBody();
				
				if(A.getUserData() instanceof ContactEvent)
				{
					((ContactEvent)(A.getUserData())).beginContact(B, contact.getWorldManifold().getNormal());
				}
				
				if(B.getUserData() instanceof ContactEvent)
				{
					((ContactEvent)(B.getUserData())).beginContact(A, contact.getWorldManifold().getNormal().mul(-1));
				}
						
			}

			@Override
			public void endContact(Contact contact) {

				Body A = contact.getFixtureA().getBody();
				Body B = contact.getFixtureB().getBody();
				
				if(A.getUserData() instanceof ContactEvent)
				{
					((ContactEvent)(A.getUserData())).endContact(B, contact.getWorldManifold().getNormal());
				}
				
				if(B.getUserData() instanceof ContactEvent)
				{
					((ContactEvent)(B.getUserData())).endContact(A, contact.getWorldManifold().getNormal().mul(-1));
				}
				
			}

			@Override
			public void preSolve(Contact contact, Manifold oldManifold) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void postSolve(Contact contact, ContactImpulse impulse) {
				// TODO Auto-generated method stub
				
			}});
		
		final Shape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2);
		final Shape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2);
		final Shape left = new Rectangle(0, 0, 2, CAMERA_HEIGHT);
		final Shape right = new Rectangle(CAMERA_WIDTH - 2, 0, 2, CAMERA_HEIGHT);

		final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0, 0, false, CATEGORYBIT_WHITE, MASKBITS_WHITE, (short)0);
		PhysicsFactory.createBoxBody(this.mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef);
		PhysicsFactory.createBoxBody(this.mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef);
		PhysicsFactory.createBoxBody(this.mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef);
		PhysicsFactory.createBoxBody(this.mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);

		this.mScene.attachChild(ground);
		this.mScene.attachChild(roof);
		this.mScene.attachChild(left);
		this.mScene.attachChild(right);
		
		/* UPDATE */
		this.mScene.registerUpdateHandler(new IUpdateHandler(){
			
			@Override
			public void onUpdate(float pSecondsElapsed) {
				Invoke();
			}

			@Override
			public void reset() {
				
			}
			
		});
	}

	@Override
	public Scene onLoadScene() {
	
		return null;
	}
	
	@Override
	public void onLoadComplete() {
		
	}
	
	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		
		if(pSceneTouchEvent.isActionDown()) {
			MainCharacterChangeColor();
			return true;
		}
		return false;
	}
		
	// ===========================================================
	// Methods
	// ===========================================================

	public void addListener(UpdateEmitter listener) {
		listeners.add(listener);
	}
	
	public void Invoke() {
		for (int i = 0; i < listeners.size(); i++) {
			listeners.get(i).onUpdateEmitterEvent();
		}
	}
	
	public void addComponent(PhysicalComponent component){
		mPhysicalComponentList.add(component);
	}

	public void onAccelerometerChanged(AccelerometerData pAccelerometerData) {
		final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(), pAccelerometerData.getY());
		if(mPhysicsWorld != null)
			this.mPhysicsWorld.setGravity(gravity);
		if(mSparkle != null)
			mSparkle.setVelocity(gravity);
		Vector2Pool.recycle(gravity);
	}
	
	private void MainCharacterChangeColor(){
		
        if (mSparkle.getColor() == ComponentColor.Red){
        	mSparkle.changeColor(ComponentColor.Blue);
        }
        else if (mSparkle.getColor() == ComponentColor.Blue){
        	mSparkle.changeColor(ComponentColor.Red);
        }
    }
	
	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
	
}
